package websocket

import (
	"sync"
	"sync/atomic"
	"time"

	"github.com/gogf/gf/frame/g"
	"github.com/gogf/gf/net/ghttp"
	"github.com/gogf/gf/os/gtime"
	"github.com/gogf/gf/os/gtimer"
	"github.com/gogf/gf/util/gconv"
)

type SessionLevel uint8 // 连接等级

// Session session
type Session struct {
	Id          uint64           `json:"id"`             // id
	Ip          string           `json:"ip"`             // 客户端ip地址
	Level       SessionLevel     `json:"level"`          // 连接等级
	User        *User            `json:"user,omitempty"` // 用户信息
	connectTime *gtime.Time      // 连接时间
	ws          *ghttp.WebSocket // websocket连接
	wsLocker    *sync.RWMutex    // websocket连接锁
}

// 权限越来越高
const (
	SessionLevelConnect    SessionLevel = iota + 1 // 初始连接的
	SessionLevelAnonymous                          // 匿名用户
	SessionLevelUser                               // 用户
	SessionLevelManager                            // 管理者
	SessionLevelSuperAdmin                         // 超管
)

var (
	atomicSessionId uint64 = 0
)

// NewSession 创建新的session
func NewSession(r *ghttp.Request, ws *ghttp.WebSocket) *Session {
	atomic.AddUint64(&atomicSessionId, 1)

	session := &Session{
		Id:          atomic.LoadUint64(&atomicSessionId),
		Ip:          r.GetClientIp(),
		Level:       SessionLevelConnect,
		connectTime: gtime.Now(),
		ws:          ws,
		wsLocker:    &sync.RWMutex{},
	}

	// 30秒后未授权，断开链接
	gtimer.AddOnce(30*time.Second, func() {
		defer func() {
			recover()
		}()
		if session.Level == SessionLevelConnect {
			_ = session.ws.Close()
		}
	})

	return session
}

func (s *Session) LostConnection() {
	s.wsLocker.Lock()
	defer s.wsLocker.Unlock()

	s.ws = nil
}

func (s *Session) GetConn() *ghttp.WebSocket {
	s.wsLocker.RLock()
	defer s.wsLocker.RUnlock()

	return s.ws
}

// AuthUser 授权用户
func (s *Session) AuthUser(user *User) {
	if s.Level == SessionLevelConnect {
		s.User = user
		s.Level = SessionLevelUser
		s.SendMessageFromSys(OpSAuthLogin, user)
	}
}

// Anonymous 匿名登录
func (s *Session) Anonymous() {
	if s.Level == SessionLevelConnect {
		s.Level = SessionLevelAnonymous
		s.SendMessageFromSys(OpSAuthAnonymous, s)
	}
}

// ChangeLevel 切换权限
func (s *Session) ChangeLevel(level SessionLevel) {
	if level < SessionLevelAnonymous {
		level = SessionLevelAnonymous
	} else if level > SessionLevelSuperAdmin {
		level = SessionLevelSuperAdmin
	}
	s.Level = level
	s.SendMessageFromSys(OpSSessionLevel, g.Map{`level`: level})
}

// IsLogin 是否登录
func (s *Session) IsLogin() bool {
	return s.Level != SessionLevelConnect
}

// SendTextMessage 发送文本消息
func (s *Session) SendTextMessage(msg []byte) {
	SendTextMessageToConnections([]*ghttp.WebSocket{s.ws}, msg)
}

// SendMessage 发送消息
func (s *Session) SendMessage(message *MessageRes) {
	SendMessageToConnections([]*ghttp.WebSocket{s.ws}, message)
}

// SendMessageFromSys 发送消息，来源是系统
func (s *Session) SendMessageFromSys(opcode MessageOpcode, data ...MessageResData) {
	s.SendMessage(NewResMessageBySys(opcode, data...))
}

// SendMessageFromSession 发送消息，来源是session
func (s *Session) SendMessageFromSession(opcode MessageOpcode, session *Session, data ...MessageResData) {
	s.SendMessage(NewResMessageBySession(opcode, session, data...))
}

// SendMessageFromError 发送错误消息
func (s *Session) SendMessageFromError(err *Error) {
	data := gconv.Map(err.Data)
	data[`message`] = err.Error()
	s.SendMessageFromSys(err.Opcode, data)
}
